package Jona;

/**
 * @author Xox Ix
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class Statement implements ArgObject{
	protected ArgObject[] supportConditionals = new ArgObject[0];
	protected ArgObject[] attackConditionals = new ArgObject[0];
	protected String text;
	protected ArgObject negatedStatement;
	public int argumentType = UNDEFINED;
	
	// Added
	boolean conflictSolved = false;
	public boolean addedInformation = false;
	int conflictValue = UNDEFINED;
	
	protected String name;
	

/* ********** CONSTRUCTORS *************************************** */

	public Statement() {
		this.argumentType = UNDEFINED;
		this.text="";
	}
	
	public Statement(int argumentType,String text){
		this.argumentType = argumentType;
		this.text = text;
	}
	
	public Statement(int argumentType,String text, ArgObject supporter, ArgObject attacker){
		this.argumentType = argumentType;
		this.text = text;
		addSupportingConditional(supporter);
		addAttackingConditional(attacker);
	}
	
	public Statement(int argumentType,String text, ArgObject[] supporters, ArgObject[] attackers){
		this.argumentType = argumentType;
		this.text = text;
		this.supportConditionals = supporters;
		this.attackConditionals = attackers;
	}
	


	

	
	
/* ********** GETTERS ******************************************** */
	

	public String getUnparsedText()
	{
		return text;
	}

	public int getArgumentType(){
		return argumentType;
	}

	public String getText(){
		// Parse the string for variables.
		int position=0, tokenPos;
		String parsedString="";
		while (position < text.length())
		{
			if ((tokenPos = text.indexOf("<",position)) != -1)
			{
				// Kopieer de tekst totaan de token vast
				parsedString+=text.substring(position,tokenPos);
				
				// bekijk waar de sluittoken staat, en bepaal de variabelenaam.
				int tokenEndPos = text.indexOf(">",tokenPos);
				
				if (tokenEndPos == -1)
					return "";
				String key = text.substring(tokenPos+1,tokenEndPos);
				
				// Vervang de variabelenaam door zijn inhoud, indien aanwezig.
				String result;
				if ((result = (String) Variable.get(key))!=null)
					parsedString+=result;
				else
					parsedString+=key+":Undefined ";
				
				position=tokenEndPos+1;					
					
			}
			else
			{
				parsedString+=text.substring(position,text.length());
				position = text.length();
			}
			
		}
		
		return parsedString;
	}
	
	public ArgObject[] getAttackingConditionals(){
		return attackConditionals;
	}

	public ArgObject[] getAttackers(){
		ArgObject [] att = new ArgObject[attackConditionals.length];
		int i;
		
		for (i = 0; i < attackConditionals.length; ++i) {
			att[i] = ((Conditional)attackConditionals[i]).getAntecedent();
		}
		return att;
	}

	public ArgObject[] getSupportingConditionals(){
		return supportConditionals;
	}

	public ArgObject[] getSupporters(){
		ArgObject [] sup = new ArgObject[supportConditionals.length];
		int i;
		
		for (i = 0; i < supportConditionals.length; ++i) {
			sup[i] = ((Conditional)supportConditionals[i]).getAntecedent();
		}
		return sup;
	}

	public ArgObject getNegation(){
		if (negatedStatement == null) {
			negatedStatement = new Negation(this);
		}
		return negatedStatement;
	}


	
	
/* ********** SETTERS ******************************************** */

	public void addedInformation(boolean value)
	{
		addedInformation = value;
		System.out.println(this.toString() + " addedInfo set to" + addedInformation);
	}
	
	public void setText(String text) {
		this.text = text;
	}
	
	public boolean hasName()
    {
    	return (name != null);
    }

	public void setEvaluation(int value)
	{
		conflictSolved = true;
		conflictValue = value;
		addedInformation(false);
	}
	
	
	
/* ********** CONTENT METHODS ************************************ */
	
	public int evaluate(Theory th){
		if (th == null) return EVALUATION_UNASSIGNED;
		
		if (isDefeated(th) && isUnsupported(th)) {
			//System.out.println("Statement '"+getText()+"' defeated");
			conflictSolved = false;
			conflictValue = EVALUATION_UNKNOWN;
			return ArgObject.EVALUATION_DEFEATED;
		}
		if (isUndefeated(th)) {
		//if (isUndefeated(th) && isSupported(th)) {
			//System.out.println("Statement '"+getText()+"' justified");
			conflictSolved = false;
			conflictValue = EVALUATION_UNKNOWN;
			return ArgObject.EVALUATION_UNDEFEATED;
		}
		
		if (conflictSolved && !addedInformation)
		{
			return conflictValue;
		}
	
		return EVALUATION_UNKNOWN;
	}
	
	public void removeAllAttackers() { 
		attackConditionals = new ArgObject[0];
	}
	
	public void removeAllSupporters() { 
		supportConditionals = new ArgObject[0];
	}
	
	protected ArgObject [] addToList(ArgObject [] list, ArgObject element) {
		int i, length;
		ArgObject [] temp;
		length = list.length;
		
		temp = new ArgObject[length+1];
		for (i = 0; i < length; ++i) {
			if (list[i] == element) {
				return list;
			}
			temp[i] = list[i];
		}
		temp[length] = element;
		return temp;
	}
	
	protected boolean findInList(ArgObject[] list, ArgObject element)
	{
		boolean found = false;
		int i =0;
		while(!found && i < list.length)
		{
			if(list[i]== element) found = true;
			i++;
		}
		return found;
	}
	
	protected ArgObject [] removeFromList(ArgObject [] list, ArgObject element) {
		int i, length, elemIndex;
		ArgObject [] temp;
		length = list.length;
		
		elemIndex = 0;
		while (elemIndex < length && list[elemIndex] != element) {
			elemIndex++;
		}
		if (elemIndex == length) {
			return list;
		}
		temp = new ArgObject[length-1];
		for (i = 0; i < elemIndex; ++i) {
			temp[i] = list[i];
		}
		for (i = elemIndex + 1; i < length; ++i) {
			temp[i-1] = list[i];
		}
		return temp;
	}
	
	public void addAttacker(ArgObject attacker){
		if (attacker == null) return;
		addAttackingConditional(new Conditional(attacker,getNegation()));
		addedInformation(true);
	}
	
	public void addSupporter(ArgObject supporter){
		if (supporter == null) return;
		addSupportingConditional(new Conditional(supporter,this));
		addedInformation(true);
	}

	public void addAttackingConditional(ArgObject attacker){
		if (attacker == null) return;
		attackConditionals = addToList(attackConditionals, attacker);
		addedInformation(true);
	}
	
	public void addSupportingConditional(ArgObject supporter){
		if (supporter == null) return;
		supportConditionals = addToList(supportConditionals, supporter);
		addedInformation(true);
	}

	public void removeSupportingConditional(ArgObject supporter){
		if (supporter == null) return;
		supportConditionals = removeFromList(supportConditionals, supporter);
		addedInformation(true);
	}

	public void removeSupporter(ArgObject supporter){
		if (supporter == null) return;
		int i;
		
		for (i = 0; i < supportConditionals.length; ++i) {
			if (((Conditional)supportConditionals[i]).getAntecedent() == supporter) {
				removeSupportingConditional(supportConditionals[i]);
				addedInformation(true);
				return;
			}
		}
		
	}
	
	public void removeAttackingConditional(ArgObject attacker){
		if (attacker == null) return;
		attackConditionals = removeFromList(attackConditionals, attacker);
		addedInformation(true);
	}

	public void removeAttacker(ArgObject attacker){
		if (attacker == null) return;
		int i;
		
		for (i = 0; i < attackConditionals.length; ++i) {
			if (((Conditional)attackConditionals[i]).getAntecedent() == attacker) {
				removeAttackingConditional(attackConditionals[i]);
				addedInformation(true);
				return;
			}
		}
	}

	public String toString() {
		String rt ="";
		if(getArgumentType() == ASSUMPTION) rt += "S:";
		else if(getArgumentType() == ISSUE) rt += "I:";
		else if(getArgumentType() == UNDEFINED) rt += "U:";
		rt+= getText();
		return rt;
	}

	/**
	 * Determines whether this statement is attacked by the given statement.  
	 * @param st Statement to determine attacking relation
	 * @return
	 * true if this statement is attacked by st,
	 * false otherwise
	 */
	public boolean isAttackedBy(ArgObject st) {
		int i;
		for (i = 0; i < attackConditionals.length; ++i) {
			if (attackConditionals[i] == st) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Determines whether this statement is attacking the given statement.  
	 * @param st Statement to determine attacking relation
	 * @return
	 * true if this statement is attacking st,
	 * false otherwise
	 */
	public boolean isAttackerOf(ArgObject st) {
		if (st == null) return false;
		return st.isAttackedBy(this);
	}
	
	/**
	 * Determines whether this statement is supported by the given statement.  
	 * @param st Statement to determine supporting relation
	 * @return
	 * true if this statement is supported by st,
	 * false otherwise
	 */
	public boolean isSupportedBy(ArgObject st) {
		int i;
		for (i = 0; i < supportConditionals.length; ++i) {
			if (supportConditionals[i] == st) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Determines whether this statement is supporting the given statement.  
	 * @param st Statement to determine supporting relation
	 * @return
	 * true if this statement is supporting st,
	 * false otherwise
	 */
	public boolean isSupporterOf(ArgObject st) {
		if (st == null) return false;
		return st.isSupportedBy(this);
	}
	
	
	public void setArgumentType(int type){
		argumentType = type;
	}
	
	/**
	 * Determines whether the given theory has a statement 
	 * that is positively supporting this statement.
	 * @param th Theory to determine support
	 * @return
	 * true if there is an undefeated statement in th supporting this 
	 * statement or this statement is an assumption without supporters in th,
	 * false otherwise
	 */
	protected boolean isSupported(Theory th) {
		int i, valSup, valCond, supCount;
		supCount = 0;
		for (i = 0; i < supportConditionals.length; ++i) {
			valCond = th.getValue(supportConditionals[i]);
			valSup = th.getValue(((Conditional)supportConditionals[i]).getAntecedent());
			if (valSup == ArgObject.EVALUATION_UNDEFEATED && valCond == ArgObject.EVALUATION_UNDEFEATED) {
				return true;
			}
			if (valSup != ArgObject.EVALUATION_UNASSIGNED && valCond != ArgObject.EVALUATION_UNASSIGNED) {
				supCount++;
			}
		}
		if (supCount == 0 && getArgumentType() == ArgObject.ASSUMPTION) {
			return true;
		}
		return false;
	}

	/**
	 * Determines whether the given theory has a statement that 
	 * is might be supporting this statement.
	 * @param th Theory to determine support
	 * @return
	 * true if there is a statement in th supporting this statement that
	 * is not defeated,
	 * false otherwise
	 */
	protected boolean isUnsupported(Theory th) {
		int i, valSup, valCond;
		for (i = 0; i < supportConditionals.length; ++i) {
			valCond = th.getValue(supportConditionals[i]);
			valSup = th.getValue(((Conditional)supportConditionals[i]).getAntecedent());
			if (valSup != ArgObject.EVALUATION_UNASSIGNED && valSup != ArgObject.EVALUATION_DEFEATED &&
					valCond != ArgObject.EVALUATION_UNASSIGNED && valCond != ArgObject.EVALUATION_DEFEATED) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Determines whether the given theory has a statement that 
	 * is positively attacking this statement.
	 * @param th Theory to determine attack
	 * @return
	 * true if there is an undefeated statement in th attacking 
	 * this statement,
	 * false otherwise
	 */
	protected boolean isDefeated(Theory th) {
		int i, valAtt, valCond;
		for (i = 0; i < attackConditionals.length; ++i) {
			valCond = th.getValue(attackConditionals[i]); 
			valAtt = th.getValue(((Conditional)attackConditionals[i]).getAntecedent());
			if (valAtt == ArgObject.EVALUATION_UNDEFEATED && valCond == ArgObject.EVALUATION_UNDEFEATED) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Determines whether the given theory has a statement that 
	 * is might be attacking this statement.
	 * @param th Theory to determine attack
	 * @return
	 * true if there is a statement in th attacking this statement that
	 * is not defeated,
	 * false otherwise
	 */
	public boolean isUndefeated(Theory th) {
		int i, valAtt, valCond;
		for (i = 0; i < attackConditionals.length; ++i) {
			valCond = th.getValue(attackConditionals[i]); 
			valAtt = th.getValue(((Conditional)attackConditionals[i]).getAntecedent());
			if (valAtt != ArgObject.EVALUATION_UNASSIGNED && valAtt != ArgObject.EVALUATION_DEFEATED &&
					valCond != ArgObject.EVALUATION_UNASSIGNED && valCond != ArgObject.EVALUATION_DEFEATED) {
				//System.out.println("Defeated");
				return false;
			}
		}
		//System.out.println("Undefeated");
		return true;
	}
	
	public ArgObject giveCopy() {
		ArgObject rt = new Statement(argumentType,text,supportConditionals,attackConditionals);		
		
		return rt;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String newName) {
		name = newName;
	}

	public String getParseableText() {
		return text;
	}
}
